namespace SimpleWebServices.Security
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Xml;
    using SimpleWebServices;
    using Xunit;

    public sealed class DigestFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Digest>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Digest());
        }

        [Fact]
        public void prop_CurrentNonce_get()
        {
            DateTime date = DateTime.UtcNow.AddMinutes(1);

            string expected = Digest.FormatNonce(date);
            string actual = Digest.CurrentNonce;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Algorithm()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("Algorithm"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_CheckNonce()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("CheckNonce"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Nonce()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("Nonce"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_NonceCount()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("NonceCount"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Opaque()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("Opaque"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_QualityOfProtection()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("QualityOfProtection"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Realm()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("Realm"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Response()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("Response"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_StaleNonce_get()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("StaleNonce"))
                .TypeIs<bool>()
                .DefaultValueIs(true)
                .Result);
        }

        [Fact]
        public void prop_Uri()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("Uri"))
                .IsAutoProperty<RelativeUri>()
                .Result);
        }

        [Fact]
        public void prop_UserName()
        {
            Assert.True(new PropertyExpectations(typeof(Digest).GetProperty("UserName"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void op_FormatAuthenticate_string_objectTrue()
        {
            string realm = "example.com";
            string nonce = Digest.CurrentNonce;
            object stale = (object) true;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"{0}\", nonce=\"{1}\", opaque=\"0000000000000000\", stale={2}, algorithm=MD5, qop=\"auth\"", realm, nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_string_objectFalse()
        {
            string realm = "example.com";
            string nonce = Digest.CurrentNonce;
            object stale = (object) false;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"{0}\", nonce=\"{1}\", opaque=\"0000000000000000\", stale={2}, algorithm=MD5, qop=\"auth\"", realm, nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_string_objectInt()
        {
            string realm = "example.com";
            object stale = (object)Int32.MaxValue;

            Assert.Throws<ArgumentException>(() => Digest.FormatAuthenticate(realm, stale));
        }

        [Fact]
        public void op_FormatAuthenticate_string_objectNull()
        {
            string realm = "example.com";
            string nonce = Digest.CurrentNonce;
            object stale = null;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"{0}\", nonce=\"{1}\", opaque=\"0000000000000000\", stale={2}, algorithm=MD5, qop=\"auth\"", realm, nonce, XmlConvert.ToString(false));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_stringNull_object()
        {
            string realm = null as string;
            string nonce = Digest.CurrentNonce;
            object stale = (object) true;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"\", nonce=\"{0}\", opaque=\"0000000000000000\", stale={1}, algorithm=MD5, qop=\"auth\"", nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_stringEmpty_object()
        {
            string realm = string.Empty;
            string nonce = Digest.CurrentNonce;
            object stale = (object) true;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"\", nonce=\"{0}\", opaque=\"0000000000000000\", stale={1}, algorithm=MD5, qop=\"auth\"", nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_string_boolTrue()
        {
            string realm = "example.com";
            string nonce = Digest.CurrentNonce;
            bool stale = true;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"{0}\", nonce=\"{1}\", opaque=\"0000000000000000\", stale={2}, algorithm=MD5, qop=\"auth\"", realm, nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_string_boolFalse()
        {
            string realm = "example.com";
            string nonce = Digest.CurrentNonce;
            bool stale = false;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"{0}\", nonce=\"{1}\", opaque=\"0000000000000000\", stale={2}, algorithm=MD5, qop=\"auth\"", realm, nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_stringNull_bool()
        {
            string realm = null as string;
            string nonce = Digest.CurrentNonce;
            bool stale = true;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"\", nonce=\"{0}\", opaque=\"0000000000000000\", stale={1}, algorithm=MD5, qop=\"auth\"", nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatAuthenticate_stringEmpty_bool()
        {
            string realm = string.Empty;
            string nonce = Digest.CurrentNonce;
            bool stale = true;

            string expected = string.Format(CultureInfo.InvariantCulture, "Digest realm=\"\", nonce=\"{0}\", opaque=\"0000000000000000\", stale={1}, algorithm=MD5, qop=\"auth\"", nonce, XmlConvert.ToString((bool)stale));
            string actual = Digest.FormatAuthenticate(realm, stale);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatNonce_DateTime()
        {
            string expected = "MzEvMTIvMjAwNiAyMzo1OTo1OQ";
            string actual = Digest.FormatNonce(new DateTime(2006, 12, 31, 23, 59, 59, 0));

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            string expected = "5cd97c8a89b00d6ee7e0bf06a594650d";
            string actual = Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatResponse_stringNull_RelativeUri_string_string_string_string_string_string_string()
        {
            string method = null as string;
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_stringEmpty_RelativeUri_string_string_string_string_string_string_string()
        {
            string method = string.Empty;
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUriNull_string_string_string_string_string_string_string()
        {
            string method = "Get";
            RelativeUri uri = null as string;
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUriEmpty_string_string_string_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = string.Empty;
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_stringNull_string_string_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = null as string;
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_stringEmpty_string_string_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = string.Empty;
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_stringNull_string_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = null as string;
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_stringEmpty_string_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = string.Empty;
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_stringNull_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = null as string;
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_stringEmpty_string_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = string.Empty;
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_stringNull_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = null as string;
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_stringEmpty_string_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = string.Empty;
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_stringNull_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = null as string;
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_stringEmpty_string_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = string.Empty;
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_string_stringNull_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = null as string;
            string qop = "auth";

            Assert.Throws<ArgumentNullException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_string_stringEmpty_string()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = string.Empty;
            string qop = "auth";

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_string_string_stringNull()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = null as string;

            string expected = "419a0f895fa360b3f15ed0c5091ad7da";
            string actual = Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatResponse_string_RelativeUri_string_string_string_string_string_string_string_stringEmpty()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = "MTEvMDkvMjAwNiAwODo1NzozMQ";
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = string.Empty;

            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop));
        }

        [Fact]
        public void op_GetElements_string()
        {
            string value = "Digest username=\"alan.dean\",realm=\"example.com\",nonce=\"OC8yNi8yMDA2IDExOjA0OjM2IEFN\",uri=\"/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt\",cnonce=\"02437ad9573eadd61f3ee387019837d4\",nc=00000001,algorithm=MD5,response=\"bc3464e2be79de8d23929f80e339fafe\",qop=\"auth\",opaque=\"0000000000000000\"";

            IDictionary<string, string> actual = Digest.GetElements(value);

            Assert.NotNull(actual);

            Assert.Equal<int>(10, actual.Count);

            Assert.Equal<string>("alan.dean", actual["username"]);
            Assert.Equal<string>("example.com", actual["realm"]);
            Assert.Equal<string>("OC8yNi8yMDA2IDExOjA0OjM2IEFN", actual["nonce"]);
            Assert.Equal<string>("/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt", actual["uri"]);
            Assert.Equal<string>("02437ad9573eadd61f3ee387019837d4", actual["cnonce"]);
            Assert.Equal<string>("00000001", actual["nc"]);
            Assert.Equal<string>("MD5", actual["algorithm"]);
            Assert.Equal<string>("bc3464e2be79de8d23929f80e339fafe", actual["response"]);
            Assert.Equal<string>("auth", actual["qop"]);
            Assert.Equal<string>("0000000000000000", actual["opaque"]);
        }

        [Fact]
        public void op_GetElements_string_EmptyTest()
        {
            string value = "Digest";

            IDictionary<string, string> actual = Digest.GetElements(value);

            Assert.NotNull(actual);

            Assert.Equal<int>(0, actual.Count);
        }

        [Fact]
        public void op_GetElements_stringBadFormat()
        {
            Assert.Throws<FormatException>(() => Digest.GetElements("123456"));
        }

        [Fact]
        public void op_GetElements_stringBadFormat_TrimTest()
        {
            Assert.Throws<FormatException>(() => Digest.GetElements(" 123456 "));
        }

        [Fact]
        public void op_GetElements_stringBadFormat_ShortTest()
        {
            Assert.Throws<FormatException>(() => Digest.GetElements("Diges"));
        }

        [Fact]
        public void op_GetElements_stringBadFormat_ShortTrimTest()
        {
            Assert.Throws<FormatException>(() => Digest.GetElements(" Diges "));
        }

        [Fact]
        public void op_GetElements_stringEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.GetElements(string.Empty));
        }

        [Fact]
        public void op_GetElements_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => Digest.GetElements(null as string));
        }

        [Fact]
        public void op_GetMD5HashBinHex_string()
        {
            string expected = "098f6bcd4621d373cade4e832627b4f6";
            string actual = Digest.GetMD5HashBinHex("test");

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_GetMD5HashBinHex_stringEmpty()
        {
            string expected = "d41d8cd98f00b204e9800998ecf8427e";
            string actual = Digest.GetMD5HashBinHex(String.Empty);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_GetMD5HashBinHex_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => Digest.GetMD5HashBinHex(null as string));
        }

        [Fact]
        public void op_IsStaleNonce_string()
        {
            string nonce = Digest.CurrentNonce;

            Assert.False(Digest.IsStaleNonce(nonce));
        }

        [Fact]
        public void op_IsStaleNonce_string_whenFalse()
        {
            string nonce = Digest.FormatNonce(new DateTime(1999, 12, 31, 23, 59, 59, 0));

            Assert.True(Digest.IsStaleNonce(nonce));
        }

        [Fact]
        public void op_IsStaleNonce_stringNull()
        {
            Assert.True(Digest.IsStaleNonce(null as string));
        }

        [Fact]
        public void op_IsStaleNonce_stringEmpty()
        {
            Assert.True(Digest.IsStaleNonce(string.Empty));
        }

        [Fact]
        public void op_Parse_string()
        {
            string value = "Digest username=\"alan.dean\",realm=\"example.com\",nonce=\"OC8yNi8yMDA2IDExOjA0OjM2IEFN\",uri=\"/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt\",cnonce=\"02437ad9573eadd61f3ee387019837d4\",nc=00000001,algorithm=MD5,response=\"bc3464e2be79de8d23929f80e339fafe\",qop=\"auth\",opaque=\"0000000000000000\"";

            Digest actual = Digest.Parse(value);

            Assert.NotNull(actual);

            Assert.Equal<string>("alan.dean", actual.UserName);
            Assert.Equal<string>("example.com", actual.Realm);
            Assert.Equal<string>("OC8yNi8yMDA2IDExOjA0OjM2IEFN", actual.Nonce);
            Assert.Equal<string>("/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt", actual.Uri);
            Assert.Equal<string>("02437ad9573eadd61f3ee387019837d4", actual.CheckNonce);
            Assert.Equal<string>("00000001", actual.NonceCount);
            Assert.Equal<string>("MD5", actual.Algorithm);
            Assert.Equal<string>("bc3464e2be79de8d23929f80e339fafe", actual.Response);
            Assert.Equal<string>("auth", actual.QualityOfProtection);
            Assert.Equal<string>("0000000000000000", actual.Opaque);
        }

        [Fact]
        public void op_Parse_stringEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.Parse(string.Empty));
        }

        [Fact]
        public void op_Parse_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => Digest.Parse(null as string));
        }

        [Fact]
        public void op_Parse_IDictionary()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest actual = Digest.Parse(elements);

            Assert.NotNull(actual);

            Assert.Equal<string>("alan.dean", actual.UserName);
            Assert.Equal<string>("example.com", actual.Realm);
            Assert.Equal<string>("OC8yNi8yMDA2IDExOjA0OjM2IEFN", actual.Nonce);
            Assert.Equal<string>("/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt", actual.Uri);
            Assert.Equal<string>("02437ad9573eadd61f3ee387019837d4", actual.CheckNonce);
            Assert.Equal<string>("00000001", actual.NonceCount);
            Assert.Equal<string>("MD5", actual.Algorithm);
            Assert.Equal<string>("bc3464e2be79de8d23929f80e339fafe", actual.Response);
            Assert.Equal<string>("auth", actual.QualityOfProtection);
            Assert.Equal<string>("0000000000000000", actual.Opaque);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingUsernameTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            /// elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingRealmTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            /// elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingNonceTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            /// elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingUriTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            /// elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingCheckNonceTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            /// elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingNonceCountTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            /// elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingAlgorithmTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            /// elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingResponseTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            /// elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingQualityOfProtectionTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            /// elements.Add("qop", "auth");
            elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionary_MissingOpaqueTest()
        {
            IDictionary<string, string> elements = new Dictionary<string, string>();
            elements.Add("username", "alan.dean");
            elements.Add("realm", "example.com");
            elements.Add("nonce", "OC8yNi8yMDA2IDExOjA0OjM2IEFN");
            elements.Add("uri", "/static/testing/da5500af-254a-4c00-b515-cdc6394c8bf7.txt");
            elements.Add("cnonce", "02437ad9573eadd61f3ee387019837d4");
            elements.Add("nc", "00000001");
            elements.Add("algorithm", "MD5");
            elements.Add("response", "bc3464e2be79de8d23929f80e339fafe");
            elements.Add("qop", "auth");
            /// elements.Add("opaque", "0000000000000000");

            Digest.Parse(elements);
        }

        [Fact]
        public void op_Parse_IDictionaryEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => Digest.Parse(new Dictionary<string, string>()));
        }

        [Fact]
        public void op_Parse_IDictionaryNull()
        {
            Assert.Throws<ArgumentNullException>(() => Digest.Parse(null as IDictionary<string, string>));
        }

        [Fact]
        public void op_Validate_string_string_password()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = Digest.CurrentNonce;
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Digest obj = new Digest
            {
                Nonce = nonce,
                Response = Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop),
                Uri = "/test/foo.txt",
                UserName = "alan.dean",
                NonceCount = nc,
                CheckNonce = cnonce,
                QualityOfProtection = qop
            };

            Assert.True(obj.Validate(method, realm, password));
        }

        [Fact]
        public void op_Validate_string_string_password_whenStale()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = Digest.FormatNonce(DateTime.UtcNow.AddSeconds(-1));
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Digest obj = new Digest
            {
                Nonce = nonce,
                Response = Digest.FormatResponse(method, uri, userName, password, realm, nonce, nc, cnonce, qop),
                Uri = "/test/foo.txt",
                UserName = "alan.dean",
                NonceCount = nc,
                CheckNonce = cnonce,
                QualityOfProtection = qop
            };

            Assert.False(obj.Validate(method, realm, password));
        }

        [Fact]
        public void op_Validate_string_string_password_whenPasswordMismatch()
        {
            string method = "GET";
            RelativeUri uri = "/test/foo.txt";
            string userName = "alan.dean";
            string password = "password";
            string realm = "cache.example.com";
            string nonce = Digest.FormatNonce(DateTime.UtcNow.AddSeconds(-1));
            string nc = "00000001";
            string cnonce = "a0c05f4314efa120e6f648774f757d93";
            string qop = "auth";

            Digest obj = new Digest
            {
                Nonce = nonce,
                Response = Digest.FormatResponse(method, uri, userName, "not the password", realm, nonce, nc, cnonce, qop),
                Uri = "/test/foo.txt",
                UserName = "alan.dean",
                NonceCount = nc,
                CheckNonce = cnonce,
                QualityOfProtection = qop
            };

            Assert.False(obj.Validate(method, realm, password));
        }
    }
}